package com.leyou.order.service;

import com.leyou.client.UserClient;
import com.leyou.common.auth.entity.UserHolder;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.annotation.Around;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper detailMapper;
    @Autowired
    private OrderLogisticsMapper logisticsMapper;
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayHelper payHelper;

    private static String PAY_URL_PREFIX = "PAY:URL:PREFIX:";


    //下单要考虑超卖问题：保存订单
    public Long createOrder(OrderDTO orderDTO) {
        try {
            //得到分布式id
            long orderId = idWorker.nextId();
            //保存订单信息
            Order order = new Order();
            ArrayList<OrderDetail> orderDetails = new ArrayList<>();//初始化一个空的订单详情对象
            order.setOrderId(orderId);
            order.setUserId(UserHolder.getUserId());
            order.setPaymentType(orderDTO.getPaymentType());
            order.setStatus(OrderStatusEnum.INIT.value());
            order.setPostFee(0l);
            Long totalFee = 0L;
            //得到cartDTO集合
            List<CartDTO> cartDTOS = orderDTO.getCarts();
            //把list列表机构的carts集合转成map结构
            Map<Long, Integer> cartMap = cartDTOS.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //得到所有skuId的集合
            List<Long> skuIds = cartDTOS.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            //根据skuid的集合获取sku集合
            List<SkuDTO> skuDTOS = itemClient.querySkuByIds(skuIds);
            for (SkuDTO skuDTO : skuDTOS) {
                Long price = skuDTO.getPrice();//每件商品单价
                Integer num = cartMap.get(skuDTO.getId());//购买数量
                totalFee += price * num;

                //要封装OrderDetail集合
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setOrderId(orderId);
                orderDetail.setSkuId(skuDTO.getId());
                orderDetail.setTitle(skuDTO.getTitle());
                orderDetail.setPrice(skuDTO.getPrice());
                orderDetail.setNum(num);
                orderDetail.setOwnSpec(skuDTO.getOwnSpec());
                orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(),","));
                orderDetail.setCreateTime(new Date());
                orderDetail.setUpdateTime(new Date());
                orderDetails.add(orderDetail);
            }
            order.setTotalFee(totalFee);
            order.setActualFee(1l);  //实付金额
            orderMapper.insertSelective(order);
            //批量保存订单详情
            detailMapper.insertList(orderDetails);
            //保存物流信息
            AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUserId(), orderId);
            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
            orderLogistics.setOrderId(orderId);
            logisticsMapper.insertSelective(orderLogistics);
            //减库存【下单时减库存，但是要及时清理未支付订单并恢复库存。】
            itemClient.minusStock(cartMap);
            return orderId;
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

    }

    // 1.查询订单
    public OrderVO queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            // 不存在
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // 判断用户id是否正确
        Long userId = UserHolder.getUserId();
        if(!userId.equals(order.getUserId())){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        // 2. 查询订单详情
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(orderId);
        List<OrderDetail> orderDetails = detailMapper.select(orderDetail);
        if(CollectionUtils.isEmpty(orderDetails)){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        // 3.查询订单状态
        OrderLogistics orderLogistics = logisticsMapper.selectByPrimaryKey(orderId);
        if (orderLogistics == null) {
            // 不存在
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        // 4.封装数据
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        orderVO.setDetailList(BeanHelper.copyWithCollection(orderDetails, OrderDetailVO.class));
        orderVO.setLogistics(BeanHelper.copyProperties(orderLogistics, OrderLogisticsVO.class));
        return orderVO;
    }

    //创建支付url
    public String createPayUrl(Long orderId) {
        // 先看是否已经生成过：
        String key = String.format(PAY_URL_PREFIX + orderId);
        String payUrl = redisTemplate.opsForValue().get(key);
        if (!StringUtils.isBlank(payUrl)) {
            return payUrl;
        }

        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum .ORDER_NOT_FOUND);
        }

        // 判断订单状态
        Integer status = order.getStatus();
        if (!status.equals(OrderStatusEnum.INIT.value())) {
            // 订单已经支付过了，订单状态异常
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }

        // 支付金额，测试时写1
        Long actualPay = /*order.getActualPay()*/ 1L;

        // 商品描述
        String desc = "【乐优商城】商品信息";
        String url = payHelper.createOrder(orderId, actualPay, desc);

        // 存入redis，设置有效期为 2小时
        redisTemplate.opsForValue().set(key,url,2, TimeUnit.HOURS);
        return url;
    }


    //微信支付成功回调
    public void handleNotify(Map<String, String> result) {
        // 1 签名校验
        try {
            payHelper.isValidSign(result);
        } catch (Exception e) {
            log.error("【微信回调】微信签名有误！, result: {}",result, e);
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_SIGN, e);
        }
        // 2、业务校验
        payHelper.checkResultCode(result);

        // 3 校验金额数据
        String totalFeeStr = result.get("total_fee");     //实际收的金额
        String tradeNoStr = result.get("out_trade_no");  //订单号
        if (StringUtils.isEmpty(totalFeeStr) || StringUtils.isEmpty(tradeNoStr)) {
            // 回调参数中必须包含订单编号和订单金额
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_PARAM);
        }

        // 3.1 获取结果中的金额
        Long totalFee = Long.valueOf(totalFeeStr);
        // 3.2 获取订单
        Long orderId = Long.valueOf(tradeNoStr);
        Order order = orderMapper.selectByPrimaryKey(orderId);
        // 3.3.判断订单的状态，保证幂等
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
            // 订单已经支付，返回成功
            return;
        }
        // 3.4.判断金额是否一致
        if (totalFee !=/*order.getActualPay()*/ 1) {
            // 金额不符
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_PARAM);
        }

        // 4 修改订单状态
        Order orderStatus = new Order();
        orderStatus.setStatus(OrderStatusEnum.PAY_UP.value());
        orderStatus.setOrderId(orderId);
        orderStatus.setPayTime(new Date());
        int count = orderMapper.insertSelective(orderStatus);
        if (count != 1) {
            log.error("【微信回调】更新订单状态失败，订单id：{}", orderId);
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
        log.info("【微信回调】, 订单支付成功! 订单编号:{}", orderId);
    }

    //查询支付状态
    public Integer queryPayStatus(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }
}
